Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rp): Add UnauthorizedHandler #503

Merged
merged 5 commits into from
Jan 9, 2024

Conversation

jkroepke
Copy link
Contributor

@jkroepke jkroepke commented Dec 19, 2023

Any callback error which results into an unauthorized status just print as plain text to the user.

I would like to enrich the user experience and offer an HTML styled error message.

My first idea was to re-use the existing errorHandler, but it always returns http.StatusInternalServerError. The best possible solution would be an errorHandler which has the preferred http status as function input. However this breaks the function signature.

Definition of Ready

  • I am happy with the code
  • Short description of the feature/issue is added in the pr description
  • PR is linked to the corresponding user story
  • Acceptance criteria are met
  • All open todos and follow ups are defined in a new ticket and justified
  • Deviations from the acceptance criteria and design are agreed with the PO and documented.
  • No debug or dead code
  • My code has no repetitions
  • Critical parts are tested automatically
  • Where possible E2E tests are implemented
  • Documentation/examples are up-to-date
  • All non-functional requirements are met
  • Functionality of the acceptance criteria is checked manually on the dev system.

Signed-off-by: Jan-Otto Kröpke <[email protected]>
Comment on lines 74 to 76
// UnauthorizedHandler returns the handler used for unauthorized errors
UnauthorizedHandler() func(http.ResponseWriter, *http.Request, string, string)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a method to the interface would be a breaking change. For the proposed implementation we don't need to expose the method, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, we do not need to expose the method. however CodeExchangeHandler is using the interface as input. Without declare the function on the interface, the method is not available.

func CodeExchangeHandler[C oidc.IDClaims](callback CodeExchangeCallback[C], rp RelyingParty, urlParam ...URLParamOpt) http.HandlerFunc {

As I mention, I would prefer to re-use the existing rp.ErrorHandler, but it does not fit in this case here.

pkg/client/rp/relying_party.go Outdated Show resolved Hide resolved
Signed-off-by: Jan-Otto Kröpke <[email protected]>
Copy link

codecov bot commented Dec 19, 2023

Codecov Report

Attention: 26 lines in your changes are missing coverage. Please review.

Comparison is base (4d85375) 60.12% compared to head (763e05f) 59.98%.

Files Patch % Lines
pkg/client/rp/relying_party.go 0.00% 26 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #503      +/-   ##
==========================================
- Coverage   60.12%   59.98%   -0.14%     
==========================================
  Files          80       80              
  Lines        6962     6978      +16     
==========================================
  Hits         4186     4186              
- Misses       2480     2496      +16     
  Partials      296      296              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkroepke
Copy link
Contributor Author

jkroepke commented Jan 5, 2024

@muhlemmer do you an alternative solution here? If I had the choice, I would think about an breaking change which modifies the function signature of the existing ErrorHandler by accepting the http status as input parameter and use the ErrorHandler on all places. I think this is more convenient as having two functions.

@muhlemmer
Copy link
Collaborator

For this PR to the main branch you could use an optional interface:

type HasUnauthorizedHandler interface {
	// UnauthorizedHandler returns the handler used for unauthorized errors
	UnauthorizedHandler() UnauthorizedHandler
}

Then use type-assertion in a helper function to use either the new or old behavior:

func unauthorizedError(w http.ResponseWriter, r *http.Request, desc string, state string, rp RelyingParty) {
	if rp, ok := rp.(HasUnauthorizedHandler); ok {
		rp.UnauthorizedHandler()(w, r, desc, state)
		return
	}
	http.Error(w, desc, http.StatusUnauthorized)
}

And call that function where required:

if err := trySetStateCookie(w, state, rp); err != nil {
    unauthorizedError(w, r, "failed to create state cookie: "+err.Error(), state, rp)
    return
}

After we merged this we can create a new PR against the next branch and do the breaking changes for the v4 release.

@jkroepke
Copy link
Contributor Author

jkroepke commented Jan 5, 2024

Sounds interesting, I was not aware of pattern. Thanks for bringing this in.

Signed-off-by: Jan-Otto Kröpke <[email protected]>
@jkroepke jkroepke force-pushed the rp/UnauthorizedHandler branch from 7fb356a to dca7835 Compare January 5, 2024 18:36
@jkroepke jkroepke requested a review from muhlemmer January 5, 2024 18:36
@muhlemmer muhlemmer merged commit 984e31a into zitadel:main Jan 9, 2024
6 of 8 checks passed
Copy link

github-actions bot commented Jan 9, 2024

🎉 This PR is included in version 3.10.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@jkroepke jkroepke deleted the rp/UnauthorizedHandler branch January 9, 2024 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants